home *** CD-ROM | disk | FTP | other *** search
/ Network PC / Network PC.iso / amiga utilities / communication / internet / amitcp3.0b / src.lha / src / amitcp / net / sana2arp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-09-08  |  19.1 KB  |  776 lines

  1. RCS_ID_C="$Id: sana2arp.c,v 3.1 1994/02/03 04:06:52 ppessi Exp $";
  2. /*
  3.  * Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
  4.  *                    Helsinki University of Technology, Finland.
  5.  *                    All rights reserved.
  6.  *
  7.  * sana2arp.c - ARP for Sana-II Interfaces
  8.  *
  9.  * Last modified: Thu Feb  3 03:06:35 1994 ppessi
  10.  *
  11.  * HISTORY
  12.  * $Log: sana2arp.c,v $
  13.  * Revision 3.1  1994/02/03  04:06:52  ppessi
  14.  * Removed OSIOCGARP (COMPAT_43); cleaned up history
  15.  *
  16.  * Revision 1.16  1994/01/23  21:58:01  jraja
  17.  * Fixed one void return for SAS/C 6.51.
  18.  *
  19.  * Revision 1.15  1993/10/29  02:00:50  ppessi
  20.  * Fixed ARP table entry allocation policy.
  21.  */
  22.  
  23. /*
  24.  * Address Resolution Protocol.
  25.  * TODO:
  26.  *    add "inuse/lock" bit (or ref. count) along with valid bit
  27.  */
  28.  
  29. #include <conf.h>
  30.  
  31. #include <sys/param.h>
  32. #include <sys/systm.h>
  33. #include <sys/malloc.h>
  34. #include <sys/mbuf.h>
  35. #include <sys/socket.h>
  36. #include <sys/time.h>
  37. #include <sys/kernel.h>
  38. #include <sys/errno.h>
  39. #include <sys/ioctl.h>
  40. #include <sys/syslog.h>
  41. #include <sys/synch.h>
  42.  
  43. #include <net/if.h>
  44. #include <net/if_types.h>
  45. #include <netinet/in.h>
  46. #include <netinet/in_systm.h>
  47. #include <netinet/in_var.h>
  48. #include <netinet/ip.h>
  49.  
  50. #include <net/if_sana.h>
  51. #include <net/sana2arp.h>
  52.  
  53. #include <net/if_loop_protos.h>
  54.  
  55. /*
  56.  * Internet to hardware address resolution table entry
  57.  */
  58. struct    arptab {
  59.   struct arptab *at_succ;    /* doubly linked list */
  60.   struct arptab *at_pred;
  61.   struct in_addr at_iaddr;    /* internet address */
  62.   u_char         at_hwaddr[MAXADDRSANA]; /* hardware address */
  63.   u_char         at_timer;    /* minutes since last reference */
  64.   u_char         at_flags;    /* flags */
  65.   struct mbuf   *at_hold;    /* last packet until resolved/timeout */
  66. };
  67.  
  68. /*
  69.  * Global constant for ARP entry allocation
  70.  */
  71. unsigned long arpentries = ARPENTRIES;
  72.  
  73. /*
  74.  * General per interface hash table
  75.  */
  76. struct arptable {
  77.   struct SignalSemaphore atb_lock;
  78.   struct arptab         *atb_free;
  79.   struct MinList         atb_entries[ARPTAB_HSIZE];
  80. };
  81.  
  82. #define ARPTAB_LOCK(atb) (ObtainSemaphore(&atb->atb_lock))
  83. #define ARPTAB_UNLOCK(atb) (ReleaseSemaphore(&atb->atb_lock)) 
  84. #define    ARPTAB_HASH(a) ((u_long)(a) % ARPTAB_HSIZE)
  85.  
  86. extern struct ifnet loif;
  87.  
  88. int    useloopback = 0;    /* use loopback interface for local traffic */
  89.  
  90. static void arpwhohas(register struct sana_softc *ssc, struct in_addr * addr);
  91. static void in_arpinput(register struct sana_softc *ssc, struct mbuf *m);
  92. static char *sana_sprintf(register u_char *ap, int len);
  93.  
  94. /*
  95.  * Initialization routine. Allocate ARP entries.
  96.  * MUST BE CALLED AT SPLIMP.
  97.  */
  98. void
  99. alloc_arptable(struct sana_softc* ssc, int to_allocate)
  100. {
  101.   struct arptab *at;
  102.   struct arptable *atab;
  103.   int i;
  104.   
  105.   if (ssc->ss_arp.table) 
  106.     return /* (void)ssc->ss_arp.table */;
  107.  
  108. #if 0
  109.   if (to_allocate < arpentries)
  110. #endif
  111.       to_allocate = arpentries;
  112.     
  113.   atab = bsd_malloc(sizeof(*atab), M_ARPENT, M_WAITOK);
  114.   at = bsd_malloc(sizeof(*at) * to_allocate, M_ARPENT, M_WAITOK);
  115.  
  116.   if (atab && at) {
  117.     InitSemaphore(&atab->atb_lock);
  118.     for (i = 0; i < ARPTAB_HSIZE; i++)
  119.       NewList((struct List *)(atab->atb_entries + i));
  120.  
  121.     aligned_bzero(at, sizeof(*at) * to_allocate);
  122.  
  123.     at[0].at_succ = NULL;
  124.     for (i = 1; i < to_allocate; i++) {
  125.       at[i].at_succ = &at[i - 1];
  126.     }
  127.     atab->atb_free = &at[to_allocate - 1];
  128.   } else {
  129.     if (atab) bsd_free(atab, M_ARPENT);
  130.     if (at) bsd_free(at, M_ARPENT);
  131.     log(LOG_ERR, "Could not allocate ARP table for %s\n", ssc->ss_name);
  132.   }
  133.  
  134.   ssc->ss_arp.table = atab;
  135. }
  136.  
  137. /* 
  138.  * Notification function for arp entries 
  139.  */
  140. LONG 
  141. arpentries_notify(void *dummy, LONG value)
  142. {
  143.   return (ULONG)value > ARPENTRIES_MIN;
  144. }
  145.  
  146. /*
  147.  * Free an arptab entry. ARP TABLE MUST BE LOCKED
  148.  */
  149. static void
  150. arptfree(register struct arptable *atb, register struct arptab *at)
  151. {
  152.   if (at->at_hold)
  153.     m_freem(at->at_hold);
  154.  
  155.   Remove((struct Node *)at);
  156.  
  157.   if (at->at_flags & ATF_PERM) {
  158.     bsd_free(at, M_ARPENT);
  159.   } else {
  160.     at->at_hold = NULL;
  161.     at->at_timer = at->at_flags = 0;
  162.     at->at_iaddr.s_addr = 0;
  163.     at->at_succ = atb->atb_free;
  164.     atb->atb_free = at;
  165.   }
  166. }
  167.  
  168. /*
  169.  * Enter a new address in arptab. ARP TABLE MUST BE LOCKED
  170.  */
  171. static struct arptab *
  172. arptnew(u_long addr, struct arptable *atb, int permanent)
  173. {
  174.   struct arptab *at = NULL;
  175.  
  176.   if (permanent) {
  177.     at = bsd_malloc(sizeof(*at), M_ARPENT, M_WAITOK);
  178.     bzero((caddr_t)at, sizeof(*at));
  179.   } else {
  180.     at = atb->atb_free;
  181.     if (at) {
  182.       atb->atb_free = at->at_succ;
  183.     } else {
  184.       /*
  185.        * The the oldest entry is pushed out from the 
  186.        * interface table if there is no free entry.
  187.        * This should always succeed since all 
  188.        * entries can not be permanent
  189.        */
  190.       struct arptab *oldest = NULL;
  191.       int i;
  192.  
  193.       for (i = 0; i < ARPTAB_HSIZE; i++) {
  194.     for (at = (struct arptab *)atb->atb_entries[i].mlh_Head; 
  195.          at->at_succ; 
  196.          at = at->at_succ) {
  197.       if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
  198.         continue;
  199.       if (!oldest || oldest->at_timer < at->at_timer)
  200.         oldest = at;
  201.     }
  202.       }
  203.       if (oldest) {
  204.     Remove((struct Node *)oldest);
  205.     at = oldest;
  206.       } else {
  207.     at = NULL;
  208.       }
  209.     }
  210.   }
  211.   if (at) {
  212.     at->at_iaddr.s_addr = addr;
  213.     at->at_flags = ATF_INUSE;
  214.     AddHead((struct List *)(&atb->atb_entries[ARPTAB_HASH(addr)]), 
  215.         (struct Node *)at);
  216.   }
  217.   return (at);
  218. }
  219.  
  220. /*
  221.  * Locate an IP address in the ARP table
  222.  * Assume looker have locked the table
  223.  */
  224. static struct arptab*
  225. arptab_look(struct arptable *table, u_long addr)
  226. {
  227.   register struct arptab *at = (struct arptab *)
  228.     table->atb_entries[ARPTAB_HASH(addr)].mlh_Head; 
  229.  
  230.   for(;at->at_succ; at = at->at_succ) 
  231.     if (at->at_iaddr.s_addr == addr) 
  232.       return at;
  233.  
  234.   return NULL;
  235. }
  236.  
  237. /*
  238.  * Timeout routine.  Age arp_tab entries once a minute.
  239.  */
  240. void
  241. arptimer()
  242. {
  243.   struct sana_softc *ssc;
  244.   register struct arptable *atab;
  245.   register struct arptab *at, *oldest;
  246.   register i;
  247.  
  248.   for (ssc = ssq; ssc; ssc = ssc->ss_next) {
  249.     if (!(atab = ssc->ss_arp.table))
  250.       continue;
  251.     /* Lock the table */
  252.     ARPTAB_LOCK(atab);
  253.     oldest = NULL;
  254.     for (i = 0; i < ARPTAB_HSIZE; i++) {
  255.       for (at = (struct arptab *)atab->atb_entries[i].mlh_Head; 
  256.        at->at_succ; 
  257.        at = at->at_succ) {
  258.     if (at->at_flags == 0 || (at->at_flags & ATF_PERM))
  259.       continue;
  260.     if (++at->at_timer < ((at->at_flags & ATF_COM) ?
  261.                   ARPT_KILLC : ARPT_KILLI))
  262.       continue;
  263.     /* timer has expired, clear entry */
  264.     arptfree(atab, at);
  265.       }
  266.     }
  267.     ARPTAB_UNLOCK(atab);
  268.   }
  269. }
  270.  
  271. /*
  272.  * Broadcast an ARP packet, asking who has addr on interface ssc.
  273.  */
  274. static void
  275. arpwhohas(register struct sana_softc *ssc, struct in_addr *addr)
  276. {
  277.   register struct mbuf *m;
  278.   register struct s2_arppkt *s2a;
  279.   struct sockaddr_sana2 ss2;
  280.  
  281.   if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
  282.     return;
  283.   m->m_len = sizeof(*s2a);
  284.   m->m_pkthdr.len = sizeof(*s2a);
  285.   MH_ALIGN(m, sizeof(*s2a));
  286.   s2a = mtod(m, struct s2_arppkt *);
  287.   aligned_bzero_const((caddr_t)s2a, sizeof (*s2a));
  288.   m->m_flags |= M_BCAST;
  289.  
  290.   /* fill in header depending of the interface */
  291.   s2a->arp_hrd = ssc->ss_arp.hrd;
  292.   s2a->arp_pro = htons(ssc->ss_ip.type);
  293.   s2a->arp_pln = sizeof(struct in_addr); /* protocol address length */
  294.   s2a->arp_hln = ssc->ss_if.if_addrlen;  /* hardware address length */
  295.   s2a->arp_op = htons(ARPOP_REQUEST);
  296.  
  297.   /* Copy source hardware address */
  298.   bcopy((caddr_t)ssc->ss_hwaddr, 
  299.     (caddr_t)&s2a->arpdata, 
  300.     s2a->arp_hln);
  301.   /* Copy source protocol address */
  302.   bcopy((caddr_t)&ssc->ss_ipaddr, 
  303.     (caddr_t)&s2a->arpdata + s2a->arp_hln, 
  304.     s2a->arp_pln);
  305.   /* Zero target hardware address */
  306.   bzero((caddr_t)&s2a->arpdata + s2a->arp_hln + s2a->arp_pln, 
  307.     s2a->arp_hln);
  308.   /* Copy target protocol address */
  309.   bcopy((caddr_t)addr, 
  310.     (caddr_t)&s2a->arpdata + 2 * s2a->arp_hln + s2a->arp_pln, 
  311.     s2a->arp_pln);
  312.  
  313.   /* Send an ARP packet */
  314.   ss2.ss2_len = sizeof(ss2);
  315.   ss2.ss2_family = AF_UNSPEC;
  316.   ss2.ss2_type = ssc->ss_arp.type; 
  317.   (*ssc->ss_if.if_output)(&ssc->ss_if, m, (struct sockaddr *)&ss2, 
  318.               (struct rtentry *)0);
  319. }
  320.  
  321. /*
  322.  * Resolve an IP address into an SANA-II address.  If success, 
  323.  * desten is filled in.  If there is no entry in arptab,
  324.  * set one up and broadcast a request for the IP address.
  325.  * Hold onto this mbuf and resend it once the address
  326.  * is finally resolved.  A return value of 1 indicates
  327.  * that desten has been filled in and the packet should be sent
  328.  * normally; a 0 return indicates that the packet has been
  329.  * taken over here, either now or for later transmission.
  330.  *
  331.  * We do some (conservative) locking here at splimp, since
  332.  * arptab is also altered from sana poll routine 
  333.  */
  334. int
  335. arpresolve(register struct sana_softc *ssc,
  336.        struct mbuf *m,
  337.        register struct in_addr *destip,
  338.        register u_char *desten,
  339.        int *error)
  340. {
  341.   register struct arptab *at;
  342.   register struct arptable *atb;
  343.   struct sockaddr_in sin;
  344.   register struct in_ifaddr *ia;
  345.   u_long lna;
  346.  
  347.   if (m->m_flags & M_BCAST) {    /* broadcast */
  348.     return 1;
  349.   }
  350.   lna = in_lnaof(*destip);
  351.   /* if for us, use software loopback driver if up */
  352.   for (ia = in_ifaddr; ia; ia = ia->ia_next)
  353.     if ((ia->ia_ifp == &ssc->ss_if) &&
  354.     (destip->s_addr == ia->ia_addr.sin_addr.s_addr)) {
  355.       /*
  356.        * This test used to be
  357.        *    if (loif.if_flags & IFF_UP)
  358.        * It allowed local traffic to be forced
  359.        * through the hardware by configuring the loopback down.
  360.        * However, it causes problems during network configuration
  361.        * for boards that can't receive packets they send.
  362.        * It is now necessary to clear "useloopback"
  363.        * to force traffic out to the hardware.
  364.        */
  365.       if (useloopback) {
  366.     sin.sin_family = AF_INET;
  367.     sin.sin_addr = *destip;
  368.     (void) looutput(&loif, m, (struct sockaddr *)&sin, 0);
  369.     /*
  370.      * The packet has already been sent and freed.
  371.      */
  372.     return (0);
  373.       } else {
  374.     bcopy((caddr_t)ssc->ss_hwaddr, (caddr_t)desten, ssc->ss_if.if_addrlen);
  375.     return (1);
  376.       }
  377.     }
  378.  
  379.   if (ssc->ss_if.if_flags & IFF_NOARP) {
  380.     /* No arp */
  381.     log(LOG_ERR, 
  382.     "arpresolve: can't resolve address for if %s/%ld\n", 
  383.     ssc->ss_if.if_name, ssc->ss_if.if_unit);
  384.     *error = ENETUNREACH;
  385.     m_freem(m);
  386.     return (0);
  387.   } 
  388.  
  389.   /* Try to locate ARP table */ 
  390.   if (!(atb = ssc->ss_arp.table)) {
  391.     alloc_arptable(ssc, 0);
  392.     if (!(atb = ssc->ss_arp.table)) {
  393.       log(LOG_ERR, "arpresolve: memory exhausted");
  394.       *error = ENOBUFS; 
  395.       m_free(m); 
  396.       return 0;
  397.     }
  398.   }
  399.  
  400.   ARPTAB_LOCK(atb);
  401.   at = arptab_look(atb, destip->s_addr);
  402.   if (at == 0) {        /* not found */
  403.     at = arptnew(destip->s_addr, atb, FALSE);
  404.     if (at) {
  405.       at->at_hold = m;
  406.       arpwhohas(ssc, destip);
  407.     } else {
  408.       log(LOG_ERR, "arpresolve: no free entry");
  409.       *error = ENETUNREACH;
  410.       m_free(m); 
  411.     } 
  412.     ARPTAB_UNLOCK(atb);
  413.     return 0;
  414.   }
  415.  
  416.   at->at_timer = 0;        /* restart the timer */
  417.   if (at->at_flags & ATF_COM) {    /* entry IS complete */
  418.     bcopy((caddr_t)at->at_hwaddr, (caddr_t)desten, ssc->ss_if.if_addrlen);
  419.     ARPTAB_UNLOCK(atb);
  420.     return 1;
  421.   }
  422.   /*
  423.    * There is an arptab entry, but no address response yet.  
  424.    * Replace the held mbuf with this latest one.
  425.    */
  426.   if (at->at_hold)
  427.     m_freem(at->at_hold);
  428.   at->at_hold = m;
  429.   arpwhohas(ssc, destip);    /* ask again */
  430.   ARPTAB_UNLOCK(atb);
  431.   return 0;
  432. }
  433.  
  434. /*
  435.  * Called from the sana poll routine
  436.  * when ARP type packet is received.  
  437.  * Common length and type checks are done here,
  438.  * then the protocol-specific routine is called.
  439.  * In addition, a sanity check is performed on the sender
  440.  * protocol address, to catch impersonators.
  441.  */
  442. void
  443. arpinput(struct sana_softc *ssc,
  444.     struct mbuf *m,
  445.         caddr_t srcaddr)
  446. {
  447.   register struct arphdr *ar;
  448.   int proto;
  449.  
  450.   if (ssc->ss_if.if_flags & IFF_NOARP)
  451.     goto out;
  452.   if (m->m_len < sizeof(struct arphdr))
  453.     goto out;
  454.   ar = mtod(m, struct arphdr *);
  455.   if (ntohs(ar->ar_hrd) != ssc->ss_arp.hrd)
  456.     goto out;
  457.   if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
  458.     goto out;
  459.   if (ar->ar_hln != ssc->ss_if.if_addrlen) 
  460.     goto out;
  461.  
  462. #ifdef paranoid_arp_mode
  463.   /* Sanity check */
  464.   if (bcmp(srcaddr, (UBYTE*)ar + sizeof(*ar), ar->ar_hln)) {
  465.     log(LOG_ERR, "An ARP packet sent as %s", 
  466.     sana_sprintf(srcaddr, ar->ar_hln));
  467.     log(LOG_ERR, " from address: %s!!\n", 
  468.     sana_sprintf((UBYTE*)ar + sizeof(*ar), ar->ar_hln));
  469.     goto out;
  470.   }
  471. #endif
  472.  
  473.   proto = ntohs(ar->ar_pro);
  474.  
  475.   if (proto == ssc->ss_ip.type) {
  476.     in_arpinput(ssc, m);
  477.     return;
  478.   } 
  479.  
  480.  out:
  481.   m_freem(m);
  482. }
  483.  
  484. /*
  485.  * ARP for Internet protocols on SANA-II interfaces.
  486.  * Algorithm is that given in RFC 826.
  487.  */
  488. static void
  489. in_arpinput(register struct sana_softc *ssc,
  490.         struct mbuf *m)
  491. {
  492.   register struct s2_arppkt *s2a;
  493.   struct sockaddr_in sin;
  494.   struct in_addr isaddr, itaddr, myaddr;
  495.   int op, completed = 0;
  496.   caddr_t sha, spa, tha, tpa;
  497.   size_t  len = ssc->ss_if.if_addrlen;
  498.  
  499.   s2a = mtod(m, struct s2_arppkt *);
  500.   op = ntohs(s2a->arp_op);
  501.  
  502.   if (s2a->arp_pln != sizeof(struct in_addr))
  503.     goto out;
  504.  
  505.   sha = (caddr_t)&(s2a->arpdata); /* other members must be calculated */
  506.   bcopy(spa = sha + len, (caddr_t)&isaddr, sizeof (isaddr));
  507.   tha = spa + sizeof(struct in_addr);
  508.   bcopy(tpa = tha + len, (caddr_t)&itaddr, sizeof (itaddr));
  509.  
  510.  
  511.   {
  512.     register struct in_ifaddr *ia;
  513.     struct in_ifaddr *maybe_ia = 0;
  514.  
  515.     /* Check for our own ARP packets */
  516.     for (ia = in_ifaddr; ia; ia = ia->ia_next)
  517.       if (ia->ia_ifp == &ssc->ss_if) {
  518.     maybe_ia = ia;
  519.     if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
  520.         (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
  521.       break;
  522.       }
  523.     if (maybe_ia == 0)
  524.       goto out;
  525.     myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
  526.     if (!bcmp(sha, (caddr_t)ssc->ss_hwaddr, len))
  527.       goto out;            /* it's from me, ignore it. */
  528.   }
  529. #ifndef AMITCP
  530.   if (!bcmp(sha, (caddr_t)etherbroadcastaddr, ac->ac_if.if_addrlen)) {
  531.     log(LOG_ERR,
  532.     "arp: ether address is broadcast for IP address %lx!\n",
  533.     ntohl(isaddr.s_addr));
  534.     goto out;
  535.   }
  536. #endif
  537.  
  538.   /* Check for duplicate IP addresses */
  539.   if (isaddr.s_addr == myaddr.s_addr) {
  540.     log(LOG_ERR,
  541.     "duplicate IP address %lx!! sent from hardware address: %s\n",
  542.     ntohl(isaddr.s_addr), 
  543.     sana_sprintf(sha, len));
  544.     itaddr = myaddr;
  545.     if (op == ARPOP_REQUEST)
  546.       goto reply;
  547.     goto out;
  548.   }
  549.   
  550.   {
  551.     struct arptable *atb;
  552.     register struct arptab *at = NULL; /* same as "merge" flag */
  553.     
  554.     /* Try to locate ARP table */ 
  555.     if (!(atb = ssc->ss_arp.table)) {
  556.       goto reply;
  557.     }
  558.  
  559.     ARPTAB_LOCK(atb);
  560.     at = arptab_look(atb, isaddr.s_addr);
  561.  
  562.     if (at) {
  563.       bcopy(sha, (caddr_t)at->at_hwaddr, len);
  564.       if ((at->at_flags & ATF_COM) == 0)
  565.     completed = 1;
  566.       at->at_flags |= ATF_COM;
  567.       if (at->at_hold) {
  568.     sin.sin_family = AF_INET;
  569.     sin.sin_addr = isaddr;
  570.     (*ssc->ss_if.if_output)(&ssc->ss_if, at->at_hold,
  571.                    (struct sockaddr *)&sin, (struct rtentry *)0);
  572.     at->at_hold = 0;
  573.       }
  574.     }
  575.     if (at == 0 && itaddr.s_addr == myaddr.s_addr) {
  576.       /* ensure we have a table entry */
  577.       if (at = arptnew(isaddr.s_addr, atb, FALSE)) {
  578.     bcopy(sha, (caddr_t)at->at_hwaddr, len);
  579.     completed = 1;
  580.     at->at_flags |= ATF_COM;
  581.       }
  582.     }
  583.     ARPTAB_UNLOCK(atb);
  584.   }
  585.  
  586.  reply:
  587.   /*
  588.    * Reply if this is an IP request
  589.    */
  590.   if (op != ARPOP_REQUEST) 
  591.     goto out;
  592.  
  593.   if (itaddr.s_addr == myaddr.s_addr) {
  594.     /* I am the target */
  595.     bcopy(sha, tha, len);
  596.     bcopy((caddr_t)ssc->ss_hwaddr, sha, len);
  597.   } else {
  598.     /* Answer if we have a public entry */
  599.     register struct arptab *at;
  600.     
  601.     /* Try to locate ARP table */ 
  602.     if (!ssc->ss_arp.table)
  603.       goto out;
  604.  
  605.     ARPTAB_LOCK(ssc->ss_arp.table);
  606.     at = arptab_look(ssc->ss_arp.table, itaddr.s_addr);
  607.     if (at && (at->at_flags & ATF_PUBL)) {
  608.       bcopy(sha, tha, len);
  609.       bcopy(at->at_hwaddr, sha, len);
  610.     } else {
  611.       at = NULL;
  612.     }
  613.     ARPTAB_UNLOCK(ssc->ss_arp.table);
  614.     if (!at) 
  615.       goto out;
  616.   }
  617.   {
  618.     struct sockaddr_sana2 ss2;
  619.     bcopy(spa, tpa, sizeof(struct in_addr));
  620.     bcopy((caddr_t)&itaddr, spa, sizeof(struct in_addr));
  621.     s2a->arp_op = htons(ARPOP_REPLY); 
  622.  
  623.     ss2.ss2_len = sizeof(ss2);
  624.     ss2.ss2_family = AF_UNSPEC;
  625.     ss2.ss2_type = ssc->ss_arp.type;
  626.     bcopy(tha, ss2.ss2_host, len);
  627.  
  628.     m->m_flags &= ~(M_BCAST|M_MCAST);
  629.  
  630.     (*ssc->ss_if.if_output)(&ssc->ss_if, m, (struct sockaddr *)&ss2, 
  631.                 (struct rtentry *)0);
  632.     return;
  633.   }
  634.  out:
  635.   m_freem(m);
  636.   return;
  637. }
  638.  
  639. int
  640. arpioctl(cmd, data)
  641.     int cmd;
  642.     caddr_t data;
  643. {
  644.   register struct arpreq *ar = (struct arpreq *)data;
  645.   register struct arptab *at;
  646.   register struct sockaddr_in *sin;
  647.   struct arptable *atb;
  648.   struct ifaddr *ifa;
  649.   struct sana_softc *ssc;
  650.   spl_t s;
  651.  
  652.   sin = (struct sockaddr_in *)&ar->arp_pa;
  653.   sin->sin_len = sizeof(ar->arp_pa);
  654.  
  655.   if (ar->arp_pa.sa_family != AF_INET ||
  656.       ar->arp_ha.sa_family != AF_UNSPEC)
  657.     return (EAFNOSUPPORT);
  658.  
  659.   s = splimp();
  660.   if ((ifa = ifa_ifwithnet(&ar->arp_pa)) == NULL) {
  661.     splx(s);
  662.     return (ENETUNREACH);
  663.   }
  664.  
  665.   ssc = (struct sana_softc *)ifa->ifa_ifp;
  666.   splx(s);
  667.  
  668.   if (ssc->ss_if.if_type != IFT_SANA || !(atb = ssc->ss_arp.table)) {
  669.     return (EAFNOSUPPORT);
  670.   }
  671.  
  672.   ARPTAB_LOCK(atb);
  673.  
  674.   if (cmd != SIOCGARPT) {
  675.     at = arptab_look(atb, sin->sin_addr.s_addr);
  676.     if (at == NULL && cmd != SIOCSARP) {
  677.       ARPTAB_UNLOCK(atb);
  678.       return (ENXIO);
  679.     }
  680.   }
  681.  
  682.   switch (cmd) {
  683.  
  684.   case SIOCSARP:        /* set entry */
  685.     if (ar->arp_ha.sa_len > sizeof(at->at_hwaddr) + 2 ||
  686.     ar->arp_ha.sa_len != ssc->ss_if.if_addrlen + 2) {
  687.       ARPTAB_UNLOCK(atb);
  688.       return (EINVAL);
  689.     }
  690.     /*
  691.      * Free if new entry should be allocated in a different way 
  692.      */
  693.     if (at != NULL && (at->at_flags ^ ar->arp_flags) & ATF_PERM) {
  694.       arptfree(atb, at);
  695.       at = NULL;
  696.     }
  697.     if (at == NULL) {
  698.       at = arptnew(sin->sin_addr.s_addr, atb, ar->arp_flags & ATF_PERM);
  699.       if (at == NULL) {
  700.     ARPTAB_UNLOCK(atb);
  701.     return (EADDRNOTAVAIL);
  702.       }
  703.     }
  704.  
  705.     bcopy((caddr_t)ar->arp_ha.sa_data, (caddr_t)at->at_hwaddr,
  706.       ar->arp_ha.sa_len - 2);
  707.     at->at_flags = ATF_COM | ATF_INUSE | 
  708.       (ar->arp_flags & (ATF_PERM|ATF_PUBL));
  709.     at->at_timer = 0;
  710.     break;
  711.  
  712.   case SIOCDARP:        /* delete entry */
  713.     arptfree(atb, at);
  714.     break;
  715.  
  716.   case SIOCGARP:        /* get entry */
  717.     bcopy((caddr_t)at->at_hwaddr, (caddr_t)ar->arp_ha.sa_data,
  718.       ar->arp_ha.sa_len = ssc->ss_if.if_addrlen + 2);
  719.     ar->arp_flags = at->at_flags;
  720.     break;
  721.  
  722.   case SIOCGARPT:        /* get table */
  723.     {
  724.       int i, n; long siz;
  725.       register struct arptabreq *atr = (struct arptabreq *)data;
  726.       ar = atr->atr_table;
  727.       siz = ar ? atr->atr_size : 0;
  728.  
  729.       for (n = i = 0; i < ARPTAB_HSIZE; i++) {
  730.     for (at = (struct arptab *)atb->atb_entries[i].mlh_Head; 
  731.          at->at_succ; 
  732.          at = at->at_succ) {
  733.       n++;
  734.       if (siz > 0) {
  735.         struct sockaddr_in *sin = (struct sockaddr_in *)&ar->arp_pa;
  736.         sin->sin_len = sizeof(*sin);
  737.         sin->sin_family = AF_INET;
  738.         sin->sin_addr = at->at_iaddr;
  739.         bcopy((caddr_t)at->at_hwaddr, (caddr_t)ar->arp_ha.sa_data,
  740.           ar->arp_ha.sa_len = ssc->ss_if.if_addrlen + 2);
  741.         ar->arp_flags = at->at_flags;
  742.         siz--;
  743.         ar++;
  744.       }
  745.     }
  746.       }
  747.       atr->atr_size -= siz;
  748.       atr->atr_inuse = n;
  749.     }
  750.   }
  751.  
  752.   ARPTAB_UNLOCK(atb);
  753.   return 0;
  754. }
  755.  
  756. static const char *digits = "0123456789ABCDEF";
  757. /*
  758.  * Print Hardware Address
  759.  */
  760. static char *sana_sprintf(register u_char *ap, int len)
  761. {
  762.   register i;
  763.   static char addrbuf[17*3];
  764.   register unsigned char *cp = addrbuf;
  765.  
  766.   for (i = 0; i < len; ) {
  767.     *cp++ = digits[*ap >> 4];
  768.     *cp++ = digits[*ap++ & 0xf];
  769.     i++;
  770.     if (i < len) 
  771.       *cp++ = ':';
  772.   }
  773.   *cp = 0;
  774.   return (addrbuf);
  775. }
  776.